package com.xyy.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.user-expiration:86400000}")
    private Long userExpiration;

    @Value("${jwt.admin-expiration:86400000}")
    private Long adminExpiration;
    
    /**
     * 获取签名密钥
     */
    private SecretKey getSigningKey() {
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    /**
     * 生成JWT token（用户）
     */
    public String generateToken(String username, Long userId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("userId", userId);
        claims.put("type", "user");
        return createToken(claims, username);
    }

    /**
     * 生成JWT token（管理员）
     */
    public String generateAdminToken(String username, Long adminId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("adminId", adminId);
        claims.put("type", "admin");
        return createToken(claims, username);
    }

    /**
     * 生成JWT token（医生）
     */
    public String generateDoctorToken(String username, Long doctorId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("userId", doctorId); // 使用userId字段存储医生ID，保持兼容性
        claims.put("doctorId", doctorId);
        claims.put("type", "doctor");
        return createToken(claims, username);
    }

    /**
     * 创建token
     */
    private String createToken(Map<String, Object> claims, String subject) {
        String type = (String) claims.get("type");
        long expirationTime = "admin".equals(type) ? adminExpiration : userExpiration;
        
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime))
                .signWith(getSigningKey(), SignatureAlgorithm.HS512)
                .compact();
    }

    /**
     * 从token中获取用户名
     */
    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    /**
     * 从token中获取用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = getAllClaimsFromToken(token);
        return claims.get("userId", Long.class);
    }

    /**
     * 从token中获取管理员ID
     */
    public Long getAdminIdFromToken(String token) {
        Claims claims = getAllClaimsFromToken(token);
        return claims.get("adminId", Long.class);
    }

    /**
     * 从token中获取医生ID
     */
    public Long getDoctorIdFromToken(String token) {
        Claims claims = getAllClaimsFromToken(token);
        return claims.get("doctorId", Long.class);
    }

    /**
     * 从token中获取类型（user/admin）
     */
    public String getTypeFromToken(String token) {
        Claims claims = getAllClaimsFromToken(token);
        return claims.get("type", String.class);
    }

    /**
     * 获取token过期时间
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    /**
     * 从token中获取指定信息
     */
    public <T> T getClaimFromToken(String token, java.util.function.Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 从token中获取所有信息
     */
    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 检查token是否过期
     */
    public Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 验证token
     */
    public Boolean validateToken(String token, String username) {
        final String tokenUsername = getUsernameFromToken(token);
        return (username.equals(tokenUsername) && !isTokenExpired(token));
    }

    /**
     * 从请求中获取用户ID（兼容用户和医生）
     */
    public Long getUserIdFromRequest(javax.servlet.http.HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        if (token == null || token.isEmpty()) {
            throw new RuntimeException("Token不能为空");
        }
        
        try {
            return getUserIdFromToken(token);
        } catch (Exception e) {
            throw new RuntimeException("无效的Token");
        }
    }

    /**
     * 从请求中获取管理员ID
     */
    public Long getAdminIdFromRequest(javax.servlet.http.HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        if (token == null || token.isEmpty()) {
            throw new RuntimeException("Token不能为空");
        }
        
        try {
            return getAdminIdFromToken(token);
        } catch (Exception e) {
            throw new RuntimeException("无效的Token");
        }
    }

    /**
     * 从请求中获取医生ID
     */
    public Long getDoctorIdFromRequest(javax.servlet.http.HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        if (token == null || token.isEmpty()) {
            throw new RuntimeException("Token不能为空");
        }
        
        try {
            Long doctorId = getDoctorIdFromToken(token);
            if (doctorId == null) {
                // 如果没有doctorId，尝试从userId获取（兼容现有的医生登录）
                return getUserIdFromToken(token);
            }
            return doctorId;
        } catch (Exception e) {
            throw new RuntimeException("无效的Token");
        }
    }
} 